#include "CGame.h"


//Contrusctor and destructor
//
CGame::CGame(HINSTANCE hInstance, LPCSTR GameName, int iMode, bool bIsWindowed, int iFPS)
{
	m_hInstance		= hInstance;
	m_GameName		= GameName;
	mi_Mode			= iMode;
	mb_IsWindowed	= bIsWindowed;
	mi_FPS			= iFPS;
	m_BackBuffer	= NULL;

	mdw_DeltaTime	= 0;

	mp_Direct3D		= new CDxManager();

	SetScreenDimension(iMode);
}

CGame::~CGame(void)
{
	Clear();
}

//set screen dimension
void CGame::SetScreenDimension(int iMode)
{
	switch (iMode)
	{
	case SCREEN_640_480_32:
		mi_ScreenWidth	=	640;
		mi_ScreenHeight	=	480;
		mi_Depth		=	32;
		m_BackBufferFormat	=	D3DFMT_X8R8G8B8;
		break;
	case SCREEN_800_600_32:
		mi_ScreenWidth	=	800;
		mi_ScreenHeight	=	600;
		mi_Depth		=	32;
		m_BackBufferFormat	=	D3DFMT_X8R8G8B8;
		break;
	case SCREEN_1024_768_32:
		mi_ScreenWidth	=	1024;
		mi_ScreenWidth	=	768;
		mi_Depth		=	32;
		m_BackBufferFormat	=	D3DFMT_X8R8G8B8;
		break;
	default:
		break;
	}
}

//initialization method
//
void CGame::InitWindow(void)
{
	WNDCLASSEX wcex;

	wcex.cbSize			=	sizeof(WNDCLASSEX);
	wcex.style			=	CS_HREDRAW	|	CS_VREDRAW;
	wcex.cbClsExtra		=	0;
	wcex.cbWndExtra		=	0;
	wcex.hInstance		=	m_hInstance;
	wcex.hIcon			=	NULL;
	wcex.hIconSm		=	NULL;
	wcex.hCursor		=	LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground  =	(HBRUSH) (GetStockObject(WHITE_BRUSH));
	wcex.lpfnWndProc	=	(WNDPROC) (WndProc);
	wcex.lpszClassName	=	m_GameName;
	wcex.lpszMenuName	=	NULL;

	RegisterClassEx(&wcex);

	DWORD style;
	if (mb_IsWindowed)
	{
		style	=	WS_OVERLAPPEDWINDOW;
	}
	else
	{
		style =		WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP;
	}

	m_WndHandle = CreateWindow(	m_GameName,	//class's name
								m_GameName,	//game's name
								style,			//window's style
								CW_USEDEFAULT,
								CW_USEDEFAULT,
								mi_ScreenWidth,
								mi_ScreenHeight,
								NULL,
								NULL,
								m_hInstance,
								NULL);

	if (!m_WndHandle)
	{
		MessageBox(NULL, "Can not create Window!","ERROR", MB_OK);
		return;
	}

	ShowWindow(m_WndHandle, SW_SHOW);
	UpdateWindow(m_WndHandle);
}

void CGame::Init(void)
{
	InitWindow();
	mp_Direct3D->InitDirect(m_WndHandle, m_BackBufferFormat, mi_ScreenWidth, mi_ScreenHeight, mb_IsWindowed);
	mp_Direct3D->InitInput(m_WndHandle, m_hInstance);
	mp_Direct3D->GetDirectDevice()->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_BackBuffer);
	LoadResource();
}

//KeyBoard Methods
//
void CGame::UpdateKeyBoard(void)
{
		// Collect all key states first
		mp_Direct3D->GetInputDevice()->GetDeviceState( sizeof(m_KeyBuffer), (LPVOID)&m_KeyBuffer);

		if (IsKeyDown(DIK_ESCAPE)) 
		{
			PostMessage(m_WndHandle,WM_QUIT,0,0);
		}

		// Collect all buffered events
		DWORD dwElements = KEYBOARD_BUFFERED_SIZE;
		HRESULT hr = mp_Direct3D->GetInputDevice()->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), m_KeyEvents, &dwElements, 0 );

		// Scan through all data, check if the key is pressed or released
		for( DWORD i = 0; i < dwElements; i++ ) 
		{
			int KeyCode = m_KeyEvents[i].dwOfs;
			int KeyState = m_KeyEvents[i].dwData;

			if ( (KeyState & 0x80) > 0)
				OnKeyDown(KeyCode);
			else 
				OnKeyUp(KeyCode);
		}

		mp_Direct3D->GetInputDevice()->Acquire();
}

int CGame::IsKeyDown(int iKeyCode)
{
	return (m_KeyBuffer[iKeyCode] & 0x80) > 0;
}

//render a frame
//
void CGame::Render(void)
{
	if (mp_Direct3D->GetDirectDevice()->BeginScene())
	{
 		RenderFrame();
		mp_Direct3D->GetDirectDevice()->EndScene();
	}

	mp_Direct3D->GetDirectDevice()->Present(NULL, NULL, NULL, NULL);
}

void CGame::RenderFrame(void)
{
	mp_Direct3D->GetDirectDevice()->ColorFill(m_BackBuffer, NULL, D3DCOLOR_XRGB(0,0,0));
}

//run 
//
void CGame::Run(void)
{
	srand( (unsigned)time(0));
	MSG msg;
	ZeroMemory(&msg, sizeof(msg));

	//CTimer*		m_Timer = new CTimer();

	DWORD start		= GetTickCount();
	DWORD dwTPC		= 1000/mi_FPS;	//TPC  = Tick Per Count

	int iDone = 0;

	while (!iDone)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
			{
				iDone = 1;
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		
		DWORD now	= GetTickCount();
		mdw_DeltaTime = now - start;

		if ( mdw_DeltaTime >= dwTPC)
		{
			start = now;
			Render();
		}

		UpdateKeyBoard();
		ProcessInput();
	}
}

//clear
//
void CGame::Clear(void)
{
	
	mp_Direct3D->Clear();

	if (m_BackBuffer != NULL)
	{
		m_BackBuffer = NULL;
	}
}

//get properties
//
int CGame::GetScreenWidth(void)
{
	return mi_ScreenWidth;
}

int CGame::GetScreenHeight(void)
{
	return mi_ScreenHeight;
}

//other methods
//

LPDIRECT3DSURFACE9 CGame::GetBackBuffer()
{
	IDirect3DSurface9* backbuffer;
	
	if (FAILED(mp_Direct3D->GetDirectDevice()->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer)))
	{
		return NULL;
	}

	return backbuffer;
}

LPDIRECT3DSURFACE9 CGame::CreateSurfaceFromFile(LPCSTR FilePath)
{
	D3DXIMAGE_INFO ImageInfo;

	HRESULT result = D3DXGetImageInfoFromFile(FilePath, &ImageInfo);

	if (FAILED(result))
	{
		MessageBox(NULL, "Can not get image info from file!", "ERROR", MB_OK);
		return NULL;
	}

	LPDIRECT3DSURFACE9 surface; 
	mp_Direct3D->GetDirectDevice()->CreateOffscreenPlainSurface(	ImageInfo.Width, 
																ImageInfo.Height,
																D3DFMT_X8R8G8B8,
																D3DPOOL_DEFAULT,
																&surface, 
																NULL);
	result = D3DXLoadSurfaceFromFile(	surface, 
										NULL,
										NULL,
										FilePath,
										NULL,
										D3DX_DEFAULT,
										D3DCOLOR_XRGB(0,0,0),
										NULL);

	if (FAILED(result))
	{
		MessageBox(NULL, "Can not Load Surface from file!", "ERROR", MB_OK);
		return NULL;
	}

	return surface;
}

void CGame::StretchToSurface(IDirect3DSurface9* image, RECT srcRect, RECT destRect)
{
	mp_Direct3D->GetDirectDevice()->StretchRect(image, &srcRect, m_BackBuffer, &destRect, D3DTEXF_POINT);
}

//virtual method
//
void CGame::LoadResource(void){}

void CGame::OnKeyUp(int iKeyCode){}

void CGame::OnKeyDown(int iKeyCode){}

void CGame::ProcessInput(){}

void CGame::UpdateFrame() {}

LRESULT CALLBACK CGame::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;	
	}

	return DefWindowProc(hWnd, message, wParam, lParam);
}



